package com.peng.rpc.serializer;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.peng.rpc.entity.RpcRequest;
import com.peng.rpc.enumeration.RpcError;
import com.peng.rpc.enumeration.SerializerCode;
import com.peng.rpc.exception.RpcException;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/**
 * json虚拟化器：直接利用JACKSON包进行序列化
 * @author Wonderson
 * @email wpp.ds@foxmail.com
 * @date 2022/3/1 20:27
 */
@Slf4j
public class JsonSerializer implements CommonSerializer {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public byte[] serialize(Object object) {
        try {
            return objectMapper.writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            log.error("对象{}序列化失败:{}", object, e);
            throw new RpcException(RpcError.SERIALIZE_FAILED);
        }
    }

    @Override
    public Object deserialize(byte[] bytes, Class<?> clazz) {
        try {
            Object res = objectMapper.readValue(bytes, clazz);
            if (res instanceof RpcRequest) {
                res = handleRequest(res);
            }
            return res;
        } catch (IOException e) {
            log.error("反序列化失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * RpcRequest对象有一个Object[]的parameters数组，需要逐一反序列化
     * @param obj 初步反序列化得到的对象
     * @return 经过每个成员都反序列化的对象
     */
    private Object handleRequest(Object obj) throws IOException {
        RpcRequest rpcRequest = (RpcRequest) obj;
        Object[] params = rpcRequest.getParameters();
        Class<?>[] paramTypes = rpcRequest.getParamTypes();
        for (int i = 0; i < params.length; i++) {
            //A.isAssignableFrom(B): 即A类是不是B类的父类、父接口、或者两者相同类
            if (!paramTypes[i].isAssignableFrom(params[i].getClass())) {
                byte[] bytes = objectMapper.writeValueAsBytes(params[i]);
                params[i] = objectMapper.readValue(bytes, paramTypes[i]);
            }
        }
        return rpcRequest;
    }

    @Override
    public int getCode() {
        return SerializerCode.JSON.getCode();
    }

}
